/*
Rewrite the programs in Listing 57-3 ( us_xfr_sv.c ) and Listing 57-4 ( us_xfr_cl.c ) to
use the Linux-specific abstract socket namespace (Section 57.6).
*/

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <sys/un.h>
#include <sys/socket.h>
#include <pthread.h>

#include "../common/logger.h"

#define SOCKET_PATH "bambotcp"
#define BACKLOG 5
#define BUFFER_SIZE 100

static void *
client_thread_func(void *arg)
{
  struct sockaddr_un addr;
  int cfd = socket(AF_UNIX, SOCK_STREAM, 0);
  if (cfd == -1)
    log_system_error("unable to create socket");

  memset(&addr, 0, sizeof(addr));
  addr.sun_family = AF_UNIX;
  strncpy(&addr.sun_path[1], SOCKET_PATH, sizeof(addr.sun_path) - 2);

  if (connect(cfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) == -1)
    log_system_error("failed to connect");

  if (write(cfd, "hello", 5) != 5)
    log_system_error("failed to send message");

  close(cfd);
}

static pthread_t client_thread;

static void
activate_client(void)
{
  int ret = pthread_create(&client_thread, NULL, client_thread_func, NULL);
  if (ret != 0)
    log_system_error("couldn't create thread");
}

int
main(void)
{
  struct sockaddr_un addr;
  int sfd = socket(AF_UNIX, SOCK_STREAM, 0);
  if (sfd == -1)
    log_system_error("unable to create client socket");

  /*
  no need to unlink
  if (remove(SOCKET_PATH) == -1 && errno != ENOENT)
    log_system_error("unable to remove socket path");
  */
  memset(&addr, 0, sizeof(addr));
  addr.sun_family = AF_UNIX;
  strncpy(&addr.sun_path[1], SOCKET_PATH, sizeof(addr.sun_path) - 2);

  if (bind(sfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un))
      == -1) log_system_error("unable to bind");

  activate_client();
  if (listen(sfd, BACKLOG) == -1) log_system_error("unable to listen");

  int cfd;
  char buffer[BUFFER_SIZE];
  for(;;)
    {
      cfd = accept(sfd, NULL, NULL);
      if (cfd == -1) log_system_error("accept");

      ssize_t bytes;
      while ((bytes = read(cfd, buffer, BUFFER_SIZE)) > 0)
        {
          fprintf(stderr, "debug: %ld: %*s\n", bytes, bytes, buffer);
        }
      fprintf(stderr, "debug: connection finished\n");
      close(cfd);
    }

  void *result;
  pthread_join(client_thread, result);
  return EXIT_SUCCESS;
}
